package ma.controller.panels.auxillary;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.event.DocumentListener;

import ma.controller.panels.parameterpanels.CtrGeoPanel;
import ma.model.ManufacturingMethodInterface;
import ma.model.auxillary.Parameter;
import ma.view.gui.auxillary.NumericalTextField;
import ma.view.gui.parameterPanels.GeometryPanel;

/**
 * The class {@code GeometryPanelListener} controls the add and
 * subtract button that are located on a geometry setup panel.
 * The buttons are able to remove or add a geometry parameter panel set.
 * @author Oliver Eckstein
 *
 */
public class GeometryPanelListener implements ActionListener {
    private String buttonTitle;
    private ManufacturingMethodInterface manuMethod;
    private GeometryPanel panel;
    private CtrInformationPanel infoPanelCtr;    
    private CtrGeoPanel geometryController;
    
    private static List<DocumentListener> controllers =
            new ArrayList<DocumentListener>();
    
    /**
     * To create a new instance of {@code GeometryPanelButtonListener}.
     * @param buttonTitle the button's title that gets controlled.
     * @param manuMethod the {@code ManufacturingMethod} whose geometry sets
     * get added or removed.
     * @param panel the button's panel.
     * @param infoPanelCtr the information panel which shows a button to
     * start the calculation
     * @param geometryController the controller of the geometry parameter panel
     */
    public GeometryPanelListener(
            String buttonTitle,
            ManufacturingMethodInterface manuMethod,
            GeometryPanel panel,
            CtrInformationPanel infoPanelCtr,            
            CtrGeoPanel geometryController) {
        
        this.buttonTitle = buttonTitle;
        this.manuMethod = manuMethod;
        this.panel = panel;
        this.infoPanelCtr = infoPanelCtr;        
        this.geometryController = geometryController;
    }
    
    @Override
    public void actionPerformed(ActionEvent e) {
        int geometryCount = manuMethod.getSetCount();
        
        if(buttonTitle.equals("+") &&                
                geometryCount < manuMethod.getMaxGeometrySets()) {
            
            // Adds a geometry set, when the '+' button was pressed.
            manuMethod.addGeometrySet();
            geometryController.addGeometryParameterPanel(geometryCount);
            addTextFieldListenerAndRegisterObserver();
        } else if(buttonTitle.equals("-") &&
                geometryCount > 1) {
            // Subtracts a geometry set, when the '-' button was pressed.   
            
            // Detected and delete the valid input count for a whole
            // geometry set.
            int panelsCount = panel.getGeometryCount();
            ArrayList<NumericalTextField> txtFieldsToRemove =
                    panel.getGeometricValueTextFields().get(panelsCount - 1);
            
            for(NumericalTextField txtField : txtFieldsToRemove) {                
                if(txtField.isNumerical()) {
                    geometryController.removeValidInput();
                } else if(!txtField.getText().equals("")) {
                    geometryController.removeInvalidInput();
                }
            }                        
            removeTextFieldListenerAndRemoveObserver();
            panel.removeGeometryParameterPanel();            
            manuMethod.removeGeometrySet();
        }
        
        // When after deleting a geometry set the complete input is valid.
        if(geometryController.getValidInputs() ==
                (manuMethod.getUserSetParametersCount())) {
            infoPanelCtr.enableCalculation();            
            panel.setErrorStatus(false);
        } else {
            infoPanelCtr.disableCalculation();            
        }
        
        // When after deleting a geometry set the last invalid input set has
        // been deleted.
        if(geometryController.getInvalidInputs() == 0) {
            panel.setErrorStatus(false);
            infoPanelCtr.enableStoreData();
        }
        manuMethod.notifyObservers();
    }
    
    /**
     * Adds action listeners to the newly added text fields and registers
     * them as an observer at the manufacturing method.
     */
    private void addTextFieldListenerAndRegisterObserver() {
        int geometrySetsCount = panel.getGeometryCount();
        // Retrieve the last set of text fields. Another set gets added
        // behind this one. The set is identical to the last set.
        ArrayList <NumericalTextField> txtFieldSet =
                panel.getGeometricValueTextFields().get(geometrySetsCount - 1);
        String parameterAbbreviation;
        Parameter param;
        NumericalTFListener controller;
        
        for(NumericalTextField txtField : txtFieldSet) {
            parameterAbbreviation = txtField.getIdentification();
            
            // Here we get the newly created parameter in the model.
            param = manuMethod.
                    getParameter(parameterAbbreviation, geometrySetsCount - 1);
            // Associate a text field with it's parameter.
            controller = new NumericalTFListener(
                    txtField, manuMethod, param, geometryController);
            txtField.addDocumentListener(controller);
            controllers.add(controller);           
            param.registerObserver(panel);                
        }        
    }
    
    private void removeTextFieldListenerAndRemoveObserver() {
        int geometrySetsCount = panel.getGeometricValueTextFields().size();
        // Retrieve the last set of text fields. This one gets removed.        
        ArrayList <NumericalTextField> txtFieldSet =
                panel.getGeometricValueTextFields().get(geometrySetsCount - 1);
        String parameterAbbreviation;
        Parameter param;
        DocumentListener listener;
        
        for(NumericalTextField txtField : txtFieldSet) {
            parameterAbbreviation = txtField.getIdentification();          
            param = manuMethod.
                    getParameter(parameterAbbreviation, geometrySetsCount - 1);
            int lastIndex = controllers.size() - 1;
            listener = controllers.get(lastIndex);
            controllers.remove(lastIndex);
            
            txtField.removeDocumentListener(listener);
            param.removeObserver(panel);                
        }        
    }

}
